#ifndef CAMERA_H
#define CAMERA_H

//#include <iostream>

#include "src/scene/ray.h"

#include "src/math/matrix.h"
#include "src/math/transformation.h"

class Camera{
	public:
		Camera();
		Camera(const Camera &);
		Camera(unsigned int, unsigned int, double, double);
		Camera(const Vector3D&, const Vector3D&, const Vector3D&, unsigned int, unsigned int, double, double);
		~Camera();

		Camera &operator=(const Camera &);

		const Vector3D &getEye() const {return eye;};
		const Vector3D &getLookAt() const {return lookAt;};
		const Vector3D &getUp() const {return up;};
		unsigned int getM() const {return m;};
		unsigned int getN() const {return n;};
		unsigned int getMPerPixel() const {return mPerPixel;};
		unsigned int getNPerPixel() const {return nPerPixel;};
		double getFocalDistance() const {return focalDistance;};
		double getImagePlane() const {return -imagePlane;};
		double getZoom() const {return zoom;};
		double getRadius() const {return radius;};
		bool getDepthOfField() const {return depthOfField;};
		unsigned int getAntialiasingType() const {return antialiasingType;};
        unsigned int getFilterType() const {return filterType;};
        double getFilterGaussianSigma() const {return filterGaussianSigma;};
        int getFilterLaplacianNeighborhood() const {return filterLaplacianNeighborhood;};
        int getFilterLaplacianNegative() const {return filterLaplacianNegative;};
		Transformation getTransformation() const {return transform;};

		void setEye(const Vector3D &_eye) {eye = _eye; calculateLocalCoordinates();};
		void setEyeX(double _x) {eye.x = _x; calculateLocalCoordinates();};
		void setEyeY(double _y) {eye.y = _y; calculateLocalCoordinates();};
		void setEyeZ(double _z) {eye.z = _z; calculateLocalCoordinates();};

		void setLookAt(const Vector3D &_lookAt) {lookAt = _lookAt; calculateLocalCoordinates();};
		void setLookAtX(double _x) {lookAt.x = _x; calculateLocalCoordinates();};
		void setLookAtY(double _y) {lookAt.y = _y; calculateLocalCoordinates();};
		void setLookAtZ(double _z) {lookAt.z = _z; calculateLocalCoordinates();};

		void setUp(const Vector3D &_up) {up = _up; calculateLocalCoordinates();};
		void setUpX(double _x) {up.x = _x; calculateLocalCoordinates();};
		void setUpY(double _y) {up.y = _y; calculateLocalCoordinates();};
		void setUpZ(double _z) {up.z = _z; calculateLocalCoordinates();};

		void setMN(unsigned int _m, unsigned int _n) {m = _m; n = _n; setLeftRightBottomTop();};
		void setM(unsigned int _m) {m = _m; setLeftRightBottomTop();};
		void setN(unsigned int _n) {n = _n; setLeftRightBottomTop();};
		void setMPerPixel(unsigned int _m) {mPerPixel = _m;};
		void setNPerPixel(unsigned int _n) {nPerPixel = _n;};
		void setFocalDistance(double _f) {focalDistance = _f; setLeftRightBottomTop();};
		void setImagePlane(double _i) {imagePlane = -_i;setLeftRightBottomTop();};
		void setZoom(double _z) {zoom = _z; setLeftRightBottomTop();};
		void setRadius(double _r) {radius = _r;};
		void setDepthOfField(bool _dof) {depthOfField =_dof;};
		void setDepthOfField(double _f, double _r) {depthOfField = true;focalDistance = _f; setLeftRightBottomTop(); radius = _r;};
		void setAntialiasingType(unsigned int _antialiasingType) {antialiasingType = _antialiasingType;};
		void setAntialiasing(unsigned int _antialiasingType, unsigned int _m, unsigned int _n) {antialiasingType = _antialiasingType;mPerPixel = _m;nPerPixel = _n;};
        void setFilterType(unsigned int _filterType) {filterType = _filterType;};
        void setFilterGaussianSigma(double _filterGaussianSigma) {filterGaussianSigma = _filterGaussianSigma;};
        void setFilterLaplacianNeighborhood(int _filterLaplacianNeighborhood) {filterLaplacianNeighborhood = _filterLaplacianNeighborhood;};
        void setFilterLaplacianNegative(int _filterLaplacianNegative) {filterLaplacianNegative = _filterLaplacianNegative;};
        void setFilterLaplacian(int _filterLaplacianNeighborhood, int _filterLaplacianNegative) {filterLaplacianNeighborhood = _filterLaplacianNeighborhood; filterLaplacianNegative = _filterLaplacianNegative;};

		Ray getRay(unsigned int, unsigned int, unsigned int, unsigned int) const;

		void draw() const;

	private:
		Vector3D eye;//onde a camera se encontra
		Vector3D lookAt;//para onde ela está olhando (asism se tem o eixo central)
		Vector3D up;//o vetor cima
		/*com esses três valores é possivel descobrir os eixos i, j, k da camera*/
        Vector3D u, v, w;
		unsigned int m, n, mPerPixel, nPerPixel;
		double focalDistance, imagePlane, left, right, top, bottom, left_, right_, top_, bottom_, zoom, radius;

        bool depthOfField;
        unsigned int antialiasingType;
        unsigned int filterType;
        double filterGaussianSigma;
        int filterLaplacianNeighborhood, filterLaplacianNegative;

        Transformation transform;

		void calculateLocalCoordinates();
//		Vector3D getGlobalCoordinates(unsigned int, unsigned int, unsigned int = 0, unsigned int = 0) const;
		void setMatrices();
		void setLeftRightBottomTop();
};

#endif
